-- PRAGMA standard control signal mapping:
-- clk								=> clk
-- clk_48k							=> clk_48k
-- reset								=> reset
-- PAY ATTENTION:					RESET IS ACTIVE LOW
-- control_in	(0) 				=> enable
--					(4 downto 1) 	=> UNUSED
--					(7 downto 5) 	=> step_size
--
--	control_out	(0)				<= enable
--					(3 downto 1)	<= step_size
-- 
-- PCM_data_in_right				=> PCM_data_in_right
-- PCM_data_in_left				=> PCM_data_in_left
-- PCM_data_out_right			<= PCM_data_out_right
-- PCM_data_out_left				<= PCM_data_out_left

library ieee;
use ieee.std_logic_signed.all;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;

entity PRM_time_1 is
  port(
    clk				: in std_logic;
	 clk_48k			: in std_logic;
    reset			: in std_logic;
	 
	 control_in		: in std_logic_vector(7 downto 0);
	 control_out	: out std_logic_vector(3 downto 0);
	 
    PCM_data_in_right	: in std_logic_vector(15 downto 0);
	 PCM_data_in_left		: in std_logic_vector(15 downto 0);
    PCM_data_out_right	: out std_logic_vector(15 downto 0);
	 PCM_data_out_left	: out std_logic_vector(15 downto 0)
    );
end entity PRM_time_1;

architecture behaviour of PRM_time_1 is
	signal enable 					: std_logic := '0';
	
	type table is array(0 to 31) of std_logic_vector(15 downto 0);
	constant LOOKUP				: table := ("0000000000000000",
	                                       "0000011001000111",
	                                       "0000110010001011",
	                                       "0001001011001000",
	                                       "0001100011111000",
	                                       "0001111100011001",
	                                       "0010010100101000",
	                                       "0010101100011111",
	                                       "0011000011111011",
	                                       "0011011010111010",
	                                       "0011110001010110",
	                                       "0100000111001110",
	                                       "0100011100011100",
	                                       "0100110000111111",
	                                       "0101000100110011",
	                                       "0101010111110101",
	                                       "0101101010000010",
	                                       "0101111011010111",
	                                       "0110001011110010",
	                                       "0110011011001111",
	                                       "0110101001101101",
	                                       "0110110111001010",
	                                       "0111000011100010",
	                                       "0111001110110101",
	                                       "0111011001000001",
	                                       "0111100010000100",
	                                       "0111101001111101",
	                                       "0111110000101001",
	                                       "0111110110001010",
	                                       "0111111010011101",
	                                       "0111111101100010",
	                                       "0111111111011000");
	
	--frequency of the tremolo signal depends on this number
	--the base frequency is 
	--		48000 [sample_freq] / (32 [table_length] * 4 [table is 1/4 of a sine])
	--		= 375 [samples]
	--so a step size of 375 results in a tremolo frequency of 1 Hz.
	--judging by ear, a 15 Hz tremolo results in a nice effect,
	--resulting in a step size of 375/15 = 25.
	--scaling this number upwards will result in lower frequencies
	signal step_size		: integer := 25;		--48000/(4*32*15)
	
	signal intermediate	: std_logic_vector(16 downto 0);
	signal product			: std_logic_vector(29 downto 0);
	
	signal index			: integer 	:= 0;
	signal l					: integer 	:= 0;
	signal sign				: std_logic := '0';
	signal counter			: integer	:= 0;
	
begin
	
	enable					<= control_in(0);
	PCM_data_out_left 	<= intermediate(16 downto 1) + product(29 downto 14) when sign = '0' 
									else intermediate(16 downto 1) - product(29 downto 14);
	
	control_out				<= control_in(7 downto 5) & control_in(0);
	
	step_size				<= 375 when control_in(7 downto 5) = "000" else
									187 when control_in(7 downto 5) = "001" else
									125 when control_in(7 downto 5) = "010" else
									75  when control_in(7 downto 5) = "011" else
									37  when control_in(7 downto 5) = "100" else
									25  when control_in(7 downto 5) = "101" else
									19  when control_in(7 downto 5) = "110" else
									15;
	
	function_p: process(clk_48k, reset)
	begin
		if reset = '0' then
			l <= 0;
			sign <= '0';
			index	<= 0;
			counter <= STEP_SIZE;
			PCM_data_out_right 	<= (others => '0');
			intermediate			<= (others => '0');
			product					<= (others => '0');
		elsif clk_48k'event and clk_48k = '0' then
			PCM_data_out_right <= (others => '0');
			if enable = '1' then
				intermediate	<= PCM_data_in_left(15 downto 2) * "011";
				product			<= PCM_data_in_left(15 downto 2) * LOOKUP(index);
				counter <= counter - 1;
				if counter = 0 then
					l <= l + 1;
					counter <= STEP_SIZE;
					if l = 127 then
						l <= 0;
						index <= 0;
						sign <= '0';
					elsif l > 95 then
						index <= index - 1;
						sign <= '1';
					elsif l = 95 then
						sign <= '1';
					elsif l > 63 then
						index <= index + 1;
						sign <= '1';
					elsif l = 63 then
						sign <= '1';
					elsif l > 31 then
						index <= index - 1;
						sign <= '0';
					elsif l = 31 then
						sign <= '0';
					else
						index <= index + 1;
						sign <= '0';
					end if;
				end if;
			else
				intermediate 			<= PCM_data_in_left & '0';
				product					<= (others => '0');
				PCM_data_out_right 	<= PCM_data_in_right;
			end if;
		end if;
	end process;
end architecture behaviour;
